/*
 * @Author: 来自火星的码农 15122322+heyzhi@user.noreply.gitee.com
 * @Date: 2025-10-03 17:17:31
 * @LastEditors: 来自火星的码农 15122322+heyzhi@user.noreply.gitee.com
 * @LastEditTime: 2025-10-10 20:25:18
 * @FilePath: /GateServer/src/redis/redismgr.cc
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include "redismgr.h"
#include <bits/types/struct_timeval.h>
#include <cstddef>
#include <functional>
#include <hiredis/hiredis.h>
#include <cstring>
#include <hiredis/read.h>
#include <memory>
#include <string>
#include "../util/logger.h"
#include "../util/config.h"
#include "redisconnectionpool.h"
namespace Yizhi {
    static ConfigVar<std::string>::ptr g_redis_host_value=ConfigMgr::Lookup("redis.host",(std::string)"127.0.0.1","");
    static ConfigVar<int>::ptr g_redis_port_value=ConfigMgr::Lookup("redis.port",(int)6379,"");
    static ConfigVar<std::string>::ptr g_redis_psw_value=ConfigMgr::Lookup("redis.psw",(std::string)"zsby99924","");
    
    RedisMgr::RedisMgr(){
        m_conpool.reset(new RedisConnectionPool(g_redis_host_value->getvalue(),g_redis_port_value->getvalue(),g_redis_psw_value->getvalue(),5));
    }

    bool RedisMgr::connect(const std::string&host,int port){
        if(m_connected){
            close();
        }
        struct timeval time_out={1,5000};
        
        m_connect=redisConnectWithTimeout(host.c_str(),port,time_out);
        if(m_connect==nullptr||m_connect->err){
            
            if(m_connected){
                LOG_ERROR(m_connect->errstr);
                redisFree(m_connect);
                m_connect=nullptr;
            }
            else {
                LOG_ERROR("can't allocate a redisconnect");
            }

            return false;
            m_connected=false;
        }
        
        m_connected=true;
        return true;
    }


    bool RedisMgr::Auth(const std::string &password){
        if(m_connected==false||m_connect==nullptr||m_connect->err){
            return false;
        }
        m_reply=(redisReply*)redisCommand(m_connect,"Auth %s", password.c_str());

        if(m_reply==nullptr){
            LOG_ERROR("auth command false");
            return false;
        }
        bool success=false;
        if(m_reply->type!=REDIS_REPLY_ERROR){
            success=true;
            LOG_DEBUG("auth success");
        }
        else{
            LOG_ERROR("auth error");
        }
        freeReplyObject(m_reply);
        return success;
    }


    bool RedisMgr::getvalue(const std::string &key,std::string &value){
        auto con=m_conpool->GetConnection();
        if(!checkConnection(con)){
            return false;
        }
        auto guard=std::unique_ptr<redisContext,std::function<void(redisContext*)>>(con,[this](redisContext*c){
            m_conpool->ReturnConnection(c);
        });

        m_reply=(redisReply*)redisCommand(con,"GET %s", key.c_str());
        
        bool success=false;
        if(m_reply->type==REDIS_REPLY_STRING){
            value=m_reply->str;
            success=true;
        }
        else if(m_reply->type==REDIS_REPLY_NIL){
            value.clear();
            success=true;
        }
        else if(m_reply->type==REDIS_REPLY_ERROR){
            LOG_ERROR("get value error");
        }
        freeReplyObject(m_reply);
        return success;
    }

    bool RedisMgr::setvalue(const std::string &key,const std::string &value){
       auto con=m_conpool->GetConnection();
        if(!checkConnection(con)){
            return false;
        }
        auto guard=std::unique_ptr<redisContext,std::function<void(redisContext*)>>(con,[this](redisContext*c){
            m_conpool->ReturnConnection(c);
        });

        m_reply=(redisReply*)redisCommand(con,"SET %s %s",key.c_str(),value.c_str());
        
        if(m_reply==NULL){
            LOG_ERROR("set key and value false with"+value+" "+key);
            return false;
        }

        bool success=(m_reply->type!=REDIS_REPLY_ERROR);
        if(!success){
            LOG_ERROR("set value reply error");
        }
        freeReplyObject(m_reply);
        return success;
    }
     
    bool RedisMgr::del(const std::string& key){
      auto con=m_conpool->GetConnection();
        if(!checkConnection(con)){
            return false;
        }
        auto guard=std::unique_ptr<redisContext,std::function<void(redisContext*)>>(con,[this](redisContext*c){
            m_conpool->ReturnConnection(c);
        });
        m_reply=(redisReply*)redisCommand(con,"DEL %s",key.c_str());
        
        if(m_reply==NULL){
            LOG_ERROR("del command false");
            return false;
        }


        bool success=(m_reply->type!=REDIS_REPLY_ERROR);
        if(!success){
            LOG_ERROR("del value reply error");
        }
        freeReplyObject(m_reply);
        return success;
    }



    bool RedisMgr::Lpush(const std::string &key,const std::string &value){

       auto con=m_conpool->GetConnection();
        if(!checkConnection(con)){
            return false;
        }
        auto guard=std::unique_ptr<redisContext,std::function<void(redisContext*)>>(con,[this](redisContext*c){
            m_conpool->ReturnConnection(c);
        });

        m_reply=(redisReply*)redisCommand(con,"LPUSH %s %s",key.c_str(),value.c_str());
        
        if(m_reply==NULL){
            LOG_ERROR("rrush key and value false with"+value+" "+key);
            return false;
        }

        bool success=(m_reply->type!=REDIS_REPLY_ERROR);
        if(!success){
            LOG_ERROR("rrush value reply error");
        }
        freeReplyObject(m_reply);
        return success;

    }
    bool RedisMgr::Rpush(const std::string &key,const std::string &value){

      auto con=m_conpool->GetConnection();
        if(!checkConnection(con)){
            return false;
        }
        auto guard=std::unique_ptr<redisContext,std::function<void(redisContext*)>>(con,[this](redisContext*c){
            m_conpool->ReturnConnection(c);
        });

        m_reply=(redisReply*)redisCommand(con,"RPUSH %s %s",key.c_str(),value.c_str());
        
        if(m_reply==NULL){
            LOG_ERROR("rrush key and value false with"+value+" "+key);
            return false;
        }

        bool success=(m_reply->type!=REDIS_REPLY_ERROR);
        if(!success){
            LOG_ERROR("rrush value reply error");
        }
        freeReplyObject(m_reply);
        return success;

    }


    bool RedisMgr::Rpop(const std::string &key,std::string &value){
        auto con=m_conpool->GetConnection();
        if(!checkConnection(con)){
            return false;
        }
        auto guard=std::unique_ptr<redisContext,std::function<void(redisContext*)>>(con,[this](redisContext*c){
            m_conpool->ReturnConnection(c);
        });

        m_reply=(redisReply*)redisCommand(con,"RPOP %s",key.c_str());
        
        if(m_reply==NULL){
            LOG_ERROR("rrush key and value false with"+value+" "+key);
            return false;
        }

        bool success=false;
        if(m_reply->type==REDIS_REPLY_STRING){
            value=m_reply->str;
            success=true;
        }
        else if(m_reply->type==REDIS_REPLY_NIL){
            value.clear();
            success=true;
        }
        else if(m_reply->type==REDIS_REPLY_ERROR){
            LOG_ERROR("get value error");
        }
        freeReplyObject(m_reply);
        return success;

        
        freeReplyObject(m_reply);
        return success;
    }


   

    bool RedisMgr::Lpop(const std::string &key,std::string &value){
       auto con=m_conpool->GetConnection();
        if(!checkConnection(con)){
            return false;
        }
        auto guard=std::unique_ptr<redisContext,std::function<void(redisContext*)>>(con,[this](redisContext*c){
            m_conpool->ReturnConnection(c);
        });

        m_reply=(redisReply*)redisCommand(con,"LPOP %s",key.c_str());
        
        if(m_reply==NULL){
            LOG_ERROR("rrush key and value false with"+value+" "+key);
            return false;
        }

        bool success=false;
        if(m_reply->type==REDIS_REPLY_STRING){
            value=m_reply->str;
            success=true;
        }
        else if(m_reply->type==REDIS_REPLY_NIL){
            value.clear();
            success=true;
        }
        else if(m_reply->type==REDIS_REPLY_ERROR){
            LOG_ERROR("get value error");
        }
        freeReplyObject(m_reply);
        return success;

        
        freeReplyObject(m_reply);
        return success;
    }


    std::string RedisMgr::HashGet(const std::string &key, const std::string &field) {
        auto con=m_conpool->GetConnection();
        if(!checkConnection(con)){
            return "";
        }
        auto guard=std::unique_ptr<redisContext,std::function<void(redisContext*)>>(con,[this](redisContext*c){
            m_conpool->ReturnConnection(c);
        });

    
    redisReply* reply = (redisReply*)redisCommand(con, "HGET %s %s", key.c_str(), field.c_str());
    if (reply == nullptr) {
       // std::cerr << "HGET command failed" << std::endl;
        return "";
    }
    
    std::string result;
    if (reply->type == REDIS_REPLY_STRING) {
        result = std::string(reply->str, reply->len);
    } else if (reply->type == REDIS_REPLY_NIL) {
        result = ""; // 字段不存在
    } else if (reply->type == REDIS_REPLY_ERROR) {
       // std::cerr << "HGET error: " << reply->str << std::endl;
    }
    
    freeReplyObject(reply);
    return result;
    }


    bool RedisMgr:: Hashset(const std::string &key,const std::string &field,const std::string value){
        auto con=m_conpool->GetConnection();
        if(!checkConnection(con)){
            return false;
        }
        auto guard=std::unique_ptr<redisContext,std::function<void(redisContext*)>>(con,[this](redisContext*c){
            m_conpool->ReturnConnection(c);
        });

    
    redisReply* m_reply = (redisReply*)redisCommand(con, "HSET %s %s %s", key.c_str(), field.c_str(), value.c_str());
    if (m_reply == nullptr) {
        //std::cerr << "HSET command failed" << std::endl;
        LOG_ERROR("hset failed");
        return false;
    }
    
    bool success = (m_reply->type != REDIS_REPLY_ERROR);
    if (!success) {
        LOG_ERROR("hset error");
        //std::cerr << "HSET error: " << reply->str << std::endl;
    }
    
    freeReplyObject(m_reply);
    return success;
    }
    bool RedisMgr:: Hashset(const char*  key,const char* hkey ,const char*hvalue ,size_t hvalue_len){
        auto con=m_conpool->GetConnection();
        if(!checkConnection(con)){
            return false;
        }
        auto guard=std::unique_ptr<redisContext,std::function<void(redisContext*)>>(con,[this](redisContext*c){
            m_conpool->ReturnConnection(c);
        });

        const char* argv[4];
        size_t argvlen[4];

        argv[0]="HSET";
        argv[1]=key;
        argv[2]=hkey;
        argv[3]=hvalue;

        argvlen[0]=strlen(argv[0]);
        argvlen[1]=strlen(argv[1]);
        argvlen[2]=strlen(argv[2]);
        argvlen[3]=hvalue_len;



        m_reply=(redisReply*)redisCommandArgv(con,4,argv, argvlen);

        bool success=true;

        if(m_reply==nullptr||m_reply->type!=REDIS_REPLY_INTEGER){
            success=false;
            LOG_ERROR("hset error");
        }
        freeReplyObject(m_reply);
        return success;
    }

    bool RedisMgr:: Existskey(const std::string key){
        
     auto con=m_conpool->GetConnection();
        if(!checkConnection(con)){
            return false;
        }
        auto guard=std::unique_ptr<redisContext,std::function<void(redisContext*)>>(con,[this](redisContext*c){
            m_conpool->ReturnConnection(c);
        });
    redisReply* m_reply = (redisReply*)redisCommand(con, "EXISTS %s", key.c_str());
    if (m_reply == nullptr) {
        LOG_ERROR("Exist failed");
        return false;
    }
    
    bool exists = false;
    if (m_reply->type == REDIS_REPLY_INTEGER) {
        exists = (m_reply->integer == 1);
    } else if (m_reply->type == REDIS_REPLY_ERROR) {
        LOG_ERROR("Exist error");
    }
    
    freeReplyObject(m_reply);
    return exists;
    }

    void RedisMgr::  close(){
        m_conpool->close();
    }




  

    bool RedisMgr::checkConnection(){
        if(m_connected==false||m_connect==nullptr||m_connect->err){
            LOG_ERROR("conncet err");
            return false;
        }
        return true;
    }
    bool RedisMgr::checkConnection(redisContext *con){
          if(con==nullptr||con->err){
            LOG_ERROR("conncet err");
            return false;
        }
        return true;
    }


    RedisMgr::~RedisMgr(){
        close();
    }




}